package top.ywlog.permission.interceptor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import top.ywlog.permission.common.RequestHolder;
import top.ywlog.permission.exception.InterceptorException;
import top.ywlog.permission.filter.RequestWrapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/**
 * @author Durian
 * Http请求拦截记录
 */
@Slf4j
@Component
public class HttpInterceptor extends HandlerInterceptorAdapter
{
    private static final ThreadLocal<Long> START_HOLDER = new ThreadLocal<>();

    /**
     * controller处理前调用
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws InterceptorException
    {
        // 可以获取通过login过滤器放入ThreadLocal的用户信息
        try
        {
            // 获取restful风格的访问路径
            String url = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
            // 获取body中的参数
            String body = getRequestBody(request);
            // 获取restful风格的参数
            Map param = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
            log.info("request start. url:{}, body: '{}', params:{}", url, body, param);
            long start = System.currentTimeMillis();
            START_HOLDER.set(start);
            return true;
        } catch (Exception e)
        {
            removeThreadLocalInfo();
            throw new InterceptorException(e.getMessage());
        }
    }

    /**
     * preHandle()返回true时，在视图渲染前调用
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws InterceptorException
    {
        // 移除掉请求过程中使用过的RequestHolder中的ThreadLocal值
        RequestHolder.remove();
    }

    /**
     * preHandle()返回true,DispatcherServlet进行视图的渲染之后,多用于清理资源
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    {
        try
        {
            String url = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
            long start = START_HOLDER.get();
            long end = System.currentTimeMillis();
            log.info("request completed. url:{}, cost:{}ms", url, end - start);
        } catch (Exception e)
        {
            throw new InterceptorException(e.getMessage());
        }finally
        {
            removeThreadLocalInfo();
        }
    }

    private void removeThreadLocalInfo()
    {
        START_HOLDER.remove();
    }

    /**
     * 获取请求体中的参数转化为字符串
     *
     * param request
     *
     * @return String requestBody
     */
    private String getRequestBody(HttpServletRequest request) throws IOException
    {
        return new RequestWrapper(request).getBody();
    }
}
